#include "hiding.h"

int getCipher(int tag) {
    return tag ? rand() : rand() % 2;
}

void getBlockZIndex(UCHAR raw[DEGREE][DEGREE], int sx, int sy, UCHAR pixel[]) {
    int index = 0, x = 0, y = 0, i;
    while(index < (BLOCKD * BLOCKD + BLOCKD) / 2) {
        for(;y >= 0 && x < BLOCKD; x++, y--) pixel[index++] = raw[sx + x][sy + y]; y++; // 向坐下走
        for(;x >= 0 && y < BLOCKD; x--, y++) pixel[index++] = raw[sx + x][sy + y]; x++; // 向右上走
    }
    x++; y--;
    while(index < BLOCKD * BLOCKD) {
        for(;x < BLOCKD; x++, y--) pixel[index++] = raw[sx + x][sy + y]; x--, y+=2; // 向坐下走
        for(;y < BLOCKD; x--, y++) pixel[index++] = raw[sx + x][sy + y]; y--; x+=2; // 向右上走
    }
}

int getBlockRelevance(UCHAR pixel[]) {
    int relevance = 0, i;
    for(i = 1; i < BLOCKD * BLOCKD; i++) {
        relevance += abs(pixel[i] - pixel[i - 1]);
    }
    return relevance;
}

void getRelevance(UCHAR raw[DEGREE][DEGREE], int relv[]) {

    UCHAR pixel[BLOCKD * BLOCKD] = {0}; // Z形排序后的像素值

    int i, j, bcnt = 0;
    for(i = 0; i < DEGREE; i += 8) {
        for(j = 0; j < DEGREE; j += 8) {
            getBlockZIndex(raw, i, j, pixel);
            relv[bcnt++] = getBlockRelevance(pixel);
        }
    }

}

void randomCipherWrite(UCHAR raw[DEGREE][DEGREE], int rate) {
    int i, j;
    for(i = 0; i < DEGREE; i++) {
        for(j = 0; j < DEGREE; j++) {
            if(!(getCipher(1) % rate)) {
                if(!getCipher(0)) { // 嵌入0: 2i+1 -> 2i
                    if(raw[i][j] % 2) raw[i][j]--;
                } else { // 嵌入1: 2i -> 2i+1
                    if(!(raw[i][j] % 2)) raw[i][j]++;
                }
            }
        }
    }
}

void pos_reverse(UCHAR pos_raw[DEGREE][DEGREE]) {
    int i, j;
    for(i = 0; i < DEGREE; i++) {
        for(j = 0; j < DEGREE; j++) {
            if(!getCipher(0)) { // 进行正翻转
                if(!getCipher(0)) { // 嵌入0: 2i+1 -> 2i
                    if(pos_raw[i][j] % 2) pos_raw[i][j]--;
                } else { // 嵌入1: 2i -> 2i + 1
                    if(!(pos_raw[i][j] % 2)) pos_raw[i][j]++;
                }
            } else { // 进行0翻转
                /* empty */                
            }
        }
    }
}

void neg_reverse(UCHAR neg_raw[DEGREE][DEGREE]) {
    int i, j;
    for(i = 0; i < DEGREE; i++) {
        for(j = 0; j < DEGREE; j++) {
            if(!getCipher(0)) { // 进行负翻转
                if(!getCipher(0)) { // 嵌入0: 2i-1 -> 2i
                    if(neg_raw[i][j] % 2) neg_raw[i][j]++;
                } else { // 嵌入1: 2i -> 2i-1
                    if(!(neg_raw[i][j] % 2)) neg_raw[i][j]--;
                }
            } else { // 进行0翻转
                /* empty */
            }
        }
    }
}

double getRm(int raw_relv[], int mod_relv[]) {
    int i, insb = 0;
    for(i = 0; i < BLOCK_CNT; i++) {
        if(raw_relv[i] < mod_relv[i]) insb++;
    }
    return insb * 1.0 / BLOCK_CNT;
}

void writeImage(FILE *carry, UCHAR header[], UCHAR mod[DEGREE][DEGREE]) {
    int i; fwrite(header, 1, 1078, carry);
    for(i = 0; i < DEGREE; i++) {
        fwrite(mod + i, sizeof(UCHAR), DEGREE, carry);
    }
}

void readHeader(FILE *image, UCHAR header[]) {
    fread(header, 1, 1078, image);
}

void readImage(FILE *image, UCHAR raw[DEGREE][DEGREE]) {
    int i;
    for(i = 0; i < DEGREE; i++) fread(raw + i, sizeof(UCHAR), DEGREE, image);
}